/*
 * ProxyRequest.java
 *
 * Created on 2008/06/08 +0900
 *
 * $Revision: 34 $
 * $Date: 2008-08-21 17:55:48 +0000 (Thu, 21 Aug 2008) $
 */

package org.gikolet.framework.request;

import org.gikolet.framework.util.Assert;

/**
 * @author Tetsutaro (latest modification by $Author: tetsutaro.ss $)
 * @version $Revision: 34 $ $Date: 2008-08-21 17:55:48 +0000 (Thu, 21 Aug 2008) $
 */
public class ProxyRequest implements Request {
    private boolean catchThrowable;
    private Request request;
    private Runnable runnable;
    private boolean executed;
    private boolean cancel;
    private boolean canceled;
    private Throwable throwable;

    protected ProxyRequest(boolean catchThrowable) {
	this.executed = false;
	this.cancel = false;
	this.canceled = false;
    }

    public ProxyRequest(Runnable runnable) {
	this(runnable, true);
    }

    public ProxyRequest(Runnable runnable, boolean catchThrowable) {
	this(catchThrowable);

	Assert.isNotNull(request);
	this.runnable = runnable;
    }

    public ProxyRequest(Request request) {
	this(request, true);
    }

    public ProxyRequest(Request request, boolean catchThrowable) {
	this(catchThrowable);

	Assert.isNotNull(request);
	this.request = request;
    }

    public synchronized void execute() {
	if (isExecuted()) {
	    throw new RequestException("Executed.");

	}
	this.executed = true;

	if (isCancel()) {
	    this.canceled = true;

	    return;
	}
	if (isCatchThrowable()) {
	    try {
		executeCore();
	    } catch (Throwable t) {
		this.throwable = t;
	    }
	} else {
	    executeCore();
	}
    }

    protected synchronized void executeCore() {
	if (this.request != null) {
	    this.request.execute();
	} else if (this.runnable != null) {
	    this.runnable.run();
	}
    }

    public synchronized void setReset() {
	this.throwable = null;
	this.cancel = false;
	this.canceled = true;
	this.executed = false;
    }

    /**
     * 実行が終わっている場合はcancel状態はsetResetが呼ばれるまで変更できない
     */
    public synchronized void setCancel(boolean cancel) {
	if (!isExecuted()) {
	    this.cancel = cancel;
	}
    }

    public synchronized boolean isCatchThrowable() {
	return this.catchThrowable;
    }

    public synchronized boolean isCancel() {
	return this.cancel;
    }

    public synchronized boolean isCanceled() {
	return this.canceled;
    }

    public synchronized boolean isExecuted() {
	return this.executed;
    }

    public synchronized Request getRequest() {
	return this.request;
    }

    public synchronized Runnable getRunnable() {
	return this.runnable;
    }

    public synchronized Throwable getExecuteThrowable() {
	return this.throwable;
    }
}
